package ro.flashbite.game_engine.proxy
{
	import com.greensock.TweenMax;
	
	import flash.media.Sound;
	
	import ro.flashbite.game_engine.view.LoadingScreen;
	import ro.flashbite.interfaces.IDestroyable;
	import ro.flashbite.loaders.AssetManager;
	import ro.flashbite.loaders.events.AssetManagerEvent;
	import ro.flashbite.loaders.types.Asset;
	import ro.flashbite.loaders.types.SoundAsset;
	import ro.flashbite.loaders.types.consts.AssetTypes;
	import ro.flashbite.loggers.ILogger;
	import ro.flashbite.loggers.LoggerFactory;
	import ro.flashbite.sound.Sound2;
	import ro.flashbite.sound.SoundManager;
	
	public final class LoadingProxy implements IDestroyable
	{
		/**
		 * logger used for sending debug messages 
		 */
		private var _logger				:	ILogger;
		/**
		 *  assetManager instance used to load assets
		 */		
		private var _assetManager		:	AssetManager;
		/**
		 * soundManager instance used to register sounds asset
		 */		
		private var _soundManager		:	SoundManager;
		/**
		 * function to call when loading is complete
		 */		
		private var _callbackFunction	:	Function;
		/**
		 * is the sprite used to show loading process
		 */		
		private var _mcLoadingInstance	:	LoadingScreen;
		/**
		 *  holds all sound ID's of registered sounds
		 */		
		private var _registeredSoundIds	:	Array;
		private var _moduleID			:	String;
		/**
		 *  tells that loading was complete
		 */		
		private var _loadingComplete	:	Boolean;
		/**
		 * this instance will be reused to load data, so will call destroy() and after that will use it to load again
		 */				
		private var _isDestroyed		:	Boolean;
		
		public function LoadingProxy(mcLoadingInstance:LoadingScreen)
		{
			_constructor(mcLoadingInstance);
		}
		private function _constructor(mcLoadingInstance:LoadingScreen):void
		{
			//save data
			_mcLoadingInstance = mcLoadingInstance;
			//internals
			_logger = LoggerFactory.getLogger("LoadingProxy");
			//reset
			reset();
		}
		
		// ================================================================================================================================
		// PUBLIC
		// ================================================================================================================================
		
		public function reset():void
		{
			if (_assetManager) {
				_assetManager.removeEventListener(AssetManagerEvent.LOADING_COMPLETE, 	onLoadAssetsEvent);
				_assetManager.removeEventListener(AssetManagerEvent.ASSET_COMPLETE, 	onLoadAssetsEvent);
				_assetManager.removeEventListener(AssetManagerEvent.PROGRESS, 			onLoadAssetsEvent);
				
				try {
					_assetManager.unloadModule(_moduleID);
				} catch (e:Error) {if (_logger) _logger.error("Error on unloading level module ID");}
			}
			if (_soundManager) {
				if (_registeredSoundIds) {
					for each (var sndID:String in _registeredSoundIds)
						if (sndID) _soundManager.unregisterSoundByID(sndID);
				}
			}
			_registeredSoundIds = [];
			
			if (_callbackFunction != null) {
				TweenMax.killDelayedCallsTo(_callbackFunction);
				_callbackFunction = null;
			}
			
			_loadingComplete = false;
			_isDestroyed = false;
		}
		
		public function loadAndRegisterAssets(assetManager:AssetManager, 
											  soundManager:SoundManager, 
											  moduleXml:XML, 
											  moduleID:String, 
											  callbackFunc:Function):void
		{
			//save internal data
			_assetManager = assetManager;
			_soundManager = soundManager;
			_callbackFunction = callbackFunc;
			_moduleID = moduleID;
			//set init props on loading screen
			_mcLoadingInstance.reset();
			//add listeners to asset manager
			_assetManager.initFromXml(moduleXml, uint(moduleXml.@estimatedSize), _moduleID);
			_assetManager.addEventListener(AssetManagerEvent.LOADING_COMPLETE, 	onLoadAssetsEvent, false, 0, true);
			_assetManager.addEventListener(AssetManagerEvent.ASSET_COMPLETE, 	onLoadAssetsEvent, false, 0, true);
			_assetManager.addEventListener(AssetManagerEvent.PROGRESS, 			onLoadAssetsEvent, false, 0, true);
			
			_logger.debug("Real Start of AssetManager");
			//start the loading
			_assetManager.startLoad();
		}
		
		// ================================================================================================================================
		// PRIVATE
		// ================================================================================================================================
		
		private function onLoadAssetsEvent(e:AssetManagerEvent):void
		{
			if (_assetManager) {
				var evType:String = e.type,
					evTarget:Asset;
				
				switch (evType) {
					case AssetManagerEvent.ASSET_COMPLETE: 
						evTarget = e.data1; //it holds asset
						//register sounds in SoundManager
						if (evTarget) {
							if (evTarget.getType() == AssetTypes.MP3 && evTarget.getContent() is Sound) {
								var snd:Sound2 = new Sound2(),
									sndID:String = evTarget.getId();
								snd.init(evTarget.getContent() as Sound, sndID, (evTarget as SoundAsset).channelID);
								_soundManager.registerSound(snd, _moduleID);
								_registeredSoundIds.push(sndID);
							}
						} else _logger.error("Asset received from manager is null");
						break
					case AssetManagerEvent.LOADING_COMPLETE:
						//remove events
						_assetManager.removeEventListener(AssetManagerEvent.LOADING_COMPLETE, 	onLoadAssetsEvent);
						_assetManager.removeEventListener(AssetManagerEvent.ASSET_COMPLETE, 	onLoadAssetsEvent);
						_assetManager.removeEventListener(AssetManagerEvent.PROGRESS, 			onLoadAssetsEvent);
						//set as complete and show it in loadingScreen
						_loadingComplete = true;
						_logger.debug("AssetManagerEvent.LOADING_COMPLETE");
						_mcLoadingInstance.update(1);
						
						_logger.debug("_assetManager loading start assets complete");
						//call complete function
						if (_callbackFunction != null) {
							TweenMax.killDelayedCallsTo(_callbackFunction);
							TweenMax.delayedCall(.05, _callbackFunction);
							//_callbackFunction();
						}
						else _logger.error("No callback function defined. Please set a valid one");
						break;
					case AssetManagerEvent.PROGRESS:
						if (_loadingComplete) return;
						//_logger.debug("AssetManagerEvent.PROGRESS : " + e.data1);
						//update loading screen
						_mcLoadingInstance.update((e.data1 as Number) / 100);
						break;
				}
			} else {
				_logger.error("_assetManager is somehow null; Fatal error. Couldn't continue");
				return;
			}
		}
		
		// ================================================================================================================================
		// DESTRUCTOR
		// ================================================================================================================================
		
		public function destroy():void
		{
			if (_assetManager) {
				_assetManager.removeEventListener(AssetManagerEvent.LOADING_COMPLETE, 	onLoadAssetsEvent);
				_assetManager.removeEventListener(AssetManagerEvent.ASSET_COMPLETE, 	onLoadAssetsEvent);
				_assetManager.removeEventListener(AssetManagerEvent.PROGRESS, 			onLoadAssetsEvent);
				
				try {
					_assetManager.unloadModule(_moduleID);
				} catch (e:Error) {if (_logger) _logger.error("Error on unloading level module ID");}
				
				_assetManager = null;
			}
			
			if (_logger) {
				LoggerFactory.clearLogger(_logger.name);
				_logger = null;
			}
			
			if (_soundManager) {
				if (_registeredSoundIds) {
					for each (var sndID:String in _registeredSoundIds)
					if (sndID) _soundManager.unregisterSoundByID(sndID, _moduleID);
				}
				_soundManager = null;
			}
			_registeredSoundIds = null;
			
			if (_callbackFunction != null) {
				TweenMax.killDelayedCallsTo(_callbackFunction);
				_callbackFunction = null;
			}
			_mcLoadingInstance = null;
			
			_moduleID = null;
			
			_isDestroyed = true;
		}
	
		// ================================================================================================================================
		// GETTERS, SETTERS
		// ================================================================================================================================
		
		public function get moduleID():String { return _moduleID; }

		public function get isDestroyed():Boolean { return _isDestroyed; }
	}
}